package com.virtualightning.mvvm.binding

import android.util.Log
import com.virtualightning.mvvm.tools.SyncCode
import java.lang.ref.WeakReference
import kotlin.collections.HashSet

/**
 *  Anchor : Create by CimZzz
 *  Time : 2021/12/27 15:59
 *  观察主体 LiveData 数据
 */
internal class Subject<T>(
	/**
	 * 主体键值
	 */
	internal val key: String
) {
	companion object {
		/**
		 * 同步码对象
		 */
		internal val syncCode: SyncCode = SyncCode()
	}

	/**
	 * 观察者列表
	 */
	private val observerSet: HashSet<ObserverRef<T>> = HashSet()

	/**
	 * 用于移除对象的引用
	 */
	private val removeObj: ObserverRef<T> = ObserverRef(null)

	/**
	 * 内部同步码对象
	 */
	private var syncCode: Int = -1

	/**
	 * 缓存的数据
	 */
	private var value: T? = null

	/**
	 * 发送数据
	 * @param value T? 数据
	 */
	internal fun postValue(value: T?) {
		this.value = value
		this.syncCode = Subject.syncCode.nextCode()
		val iterator = observerSet.iterator()
		while(iterator.hasNext()) {
			val ref = iterator.next().get()
			if(ref == null) {
				iterator.remove()
				continue
			}
			ref.onChanged(syncCode, value)
		}
	}

	/**
	 * 数据变化回调
	 * @param callback Function1<T?, Unit> 观察者回调
	 */
	internal fun observe(callback: SubjectCallback<T>) {
		val callbackSyncCode = callback.getSyncCode()
		if(syncCode == -1) {
			syncCode = Subject.syncCode.nextCode()
		}
		else if(callbackSyncCode != -1 && callbackSyncCode != syncCode) {
			callback.onChanged(syncCode, value)
		}
		observerSet.add(ObserverRef(callback))
	}

	/**
	 * 移除观察者列表
	 * @param callback Function1<T?, Unit> 观察者回调
	 */
	internal fun removeObserver(callback: SubjectCallback<T>) {
		removeObj.innerHashCode = callback.hashCode()
		observerSet.remove(removeObj)
	}

	/**
	 * 观察者回调引用
	 */
	private open class ObserverRef<T>(referent: SubjectCallback<T>?) :
		WeakReference<SubjectCallback<T>>(referent) {
		var innerHashCode = referent?.hashCode() ?: 0

		override fun equals(other: Any?): Boolean {
			return other is ObserverRef<*> && other.innerHashCode == innerHashCode
		}

		override fun hashCode(): Int {
			return innerHashCode
		}
	}
}

/**
 * 主体回调接口
 */
interface SubjectCallback<T> {
	/**
	 * Subject 数据变化
	 * @param syncCode Int 同步码
	 * @param value T? 变化的数据
	 */
	fun onChanged(syncCode: Int, value: T?)

	/**
	 * 获取当前观察回调的同步码
	 * @return Int 同步码
	 */
	fun getSyncCode(): Int
}